package io.gitee.zhangbinhub.admin.deploy.controller

import com.fasterxml.jackson.databind.ObjectMapper
import io.gitee.zhangbinhub.acp.boot.exceptions.WebException
import io.gitee.zhangbinhub.acp.boot.log.LogAdapter
import io.gitee.zhangbinhub.acp.core.common.CommonTools
import io.gitee.zhangbinhub.admin.common.constant.CommonConstant
import io.gitee.zhangbinhub.admin.common.permission.BaseExpression
import io.gitee.zhangbinhub.admin.common.vo.InfoVo
import io.gitee.zhangbinhub.admin.deploy.constant.DeployApi
import io.gitee.zhangbinhub.admin.deploy.service.DeployFileService
import io.gitee.zhangbinhub.admin.deploy.po.FilePo
import io.gitee.zhangbinhub.admin.deploy.vo.FileVo
import io.gitee.zhangbinhub.admin.resource.server.base.BaseResourceServerController
import io.swagger.v3.oas.annotations.*
import io.swagger.v3.oas.annotations.responses.ApiResponse
import io.swagger.v3.oas.annotations.responses.ApiResponses
import io.swagger.v3.oas.annotations.security.SecurityRequirement
import io.swagger.v3.oas.annotations.tags.Tag
import jakarta.servlet.http.HttpServletRequest
import jakarta.servlet.http.HttpServletResponse
import jakarta.validation.Valid
import jakarta.validation.constraints.NotBlank
import org.bouncycastle.util.encoders.Base64
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.http.HttpHeaders
import org.springframework.http.MediaType
import org.springframework.http.ResponseEntity
import org.springframework.security.access.prepost.PreAuthorize
import org.springframework.validation.annotation.Validated
import org.springframework.web.bind.annotation.*
import org.springframework.web.multipart.MultipartFile

@Validated
@RestController
@RequestMapping(DeployApi.basePath)
@Tag(name = "文件管理")
class DeployFileController @Autowired
constructor(
    logAdapter: LogAdapter,
    private val objectMapper: ObjectMapper,
    private val deployFileService: DeployFileService
) : BaseResourceServerController(logAdapter) {
    @Operation(
        summary = "创建文件夹", security = [
            SecurityRequirement(name = HttpHeaders.AUTHORIZATION),
            SecurityRequirement(name = CommonConstant.ACCESS_TOKEN)]
    )
    @ApiResponses(ApiResponse(responseCode = "400", description = "参数校验不通过；"))
    @PreAuthorize(BaseExpression.superOnly)
    @PutMapping(value = [DeployApi.file], produces = [MediaType.APPLICATION_JSON_VALUE])
    @Throws(WebException::class)
    fun createFold(@RequestBody @Valid filePo: FilePo): ResponseEntity<FileVo> {
        return deployFileService.createFold(filePo.path ?: "", filePo.name!!).let {
            ResponseEntity.ok(it)
        }
    }

    @Operation(
        summary = "查询服务器文件", security = [
            SecurityRequirement(name = HttpHeaders.AUTHORIZATION),
            SecurityRequirement(name = CommonConstant.ACCESS_TOKEN)]
    )
    @PreAuthorize(BaseExpression.superOnly)
    @GetMapping(value = [DeployApi.file], produces = [MediaType.APPLICATION_JSON_VALUE])
    @Throws(WebException::class)
    fun queryFile(
        @Parameter(description = "路径", required = false)
        @RequestParam(name = "path", required = false) path: String?,
        @Parameter(description = "名称", required = false)
        @RequestParam(name = "name", required = false) name: String?
    ): ResponseEntity<List<FileVo>> = (path?.let {
        String(Base64.decode(it), CommonTools.getDefaultCharset())
    } ?: "").let { basePath ->
        (name?.let {
            String(Base64.decode(it), CommonTools.getDefaultCharset())
        } ?: "").let { filterName ->
            ResponseEntity.ok(deployFileService.fileList(basePath, filterName))
        }
    }

    @Operation(
        summary = "上传文件", security = [
            SecurityRequirement(name = HttpHeaders.AUTHORIZATION),
            SecurityRequirement(name = CommonConstant.ACCESS_TOKEN)]
    )
    @ApiResponses(ApiResponse(responseCode = "400", description = "参数校验不通过；"))
    @PreAuthorize(BaseExpression.superOnly)
    @PostMapping(value = [DeployApi.file], produces = [MediaType.APPLICATION_JSON_VALUE])
    @Throws(WebException::class)
    fun uploadFile(
        @Parameter(description = "路径", required = false)
        @RequestParam(name = "path", required = false) path: String?,
        @Parameter(description = "文件", required = true)
        @RequestPart(name = "file") file: MultipartFile
    ): ResponseEntity<FileVo> {
        if (file.isEmpty) {
            throw WebException("请选择需要上传的文件")
        }
        deployFileService.uploadFile(path ?: "", file).let {
            return ResponseEntity.ok(it)
        }
    }

    @Operation(
        summary = "删除文件", security = [
            SecurityRequirement(name = HttpHeaders.AUTHORIZATION),
            SecurityRequirement(name = CommonConstant.ACCESS_TOKEN)]
    )
    @ApiResponses(ApiResponse(responseCode = "400", description = "参数校验不通过；"))
    @PreAuthorize(BaseExpression.superOnly)
    @DeleteMapping(value = [DeployApi.file], produces = [MediaType.APPLICATION_JSON_VALUE])
    @Throws(WebException::class)
    fun deleteFile(@RequestBody @Valid filePo: FilePo): ResponseEntity<InfoVo> {
        return deployFileService.deleteFile(filePo.path ?: "", filePo.name!!).let {
            ResponseEntity.ok(InfoVo(message = "文件删除成功"))
        }
    }

    @Operation(
        summary = "下载文件", security = [
            SecurityRequirement(name = HttpHeaders.AUTHORIZATION),
            SecurityRequirement(name = CommonConstant.ACCESS_TOKEN)]
    )
    @ApiResponses(ApiResponse(responseCode = "200", description = "请求成功，进行文件下载；"))
    @GetMapping(value = [DeployApi.fileDownLoad], produces = [MediaType.ALL_VALUE])
    @Throws(WebException::class)
    fun downloadFile(
        request: HttpServletRequest, response: HttpServletResponse,
        @Parameter(description = "文件内容", required = true)
        @NotBlank(message = "文件内容不能为空")
        @RequestParam(name = "params") params: String
    ) {
        val fileContent = objectMapper.readValue(params, FilePo::class.java)
        if (CommonTools.isNullStr(fileContent.name)) {
            throw WebException("文件名称不能为空")
        }
        val basePath = String(Base64.decode(fileContent.path), CommonTools.getDefaultCharset())
        val fileName = String(Base64.decode(fileContent.name), CommonTools.getDefaultCharset())
        deployFileService.doDownLoadFile(request, response, basePath, fileName)
    }
}